#pragma once
#include <iostream>
#include <sys/epoll.h>
#include <unistd.h>
#include "Log.hpp"
#include "Common.hpp"

using namespace LogModule;

class Epoller
{
public:
    Epoller()
        : _epfd(-1)
    {
        // 创建epoll模型
        _epfd = epoll_create(128);
        if (_epfd < 0)
        {
            // 创建失败
            LOG(LogLevel::FATAL) << "epoll_create error!!";
            exit(EPOLL_CREATE_ERR);
        }
        LOG(LogLevel::DEBUG) << "create epoll success , _epfd: " << _epfd;
    }

    // 添加event的接口
    // 新增对特定fd要关心的事件
    void AddEvent(int sockfd, uint32_t events)
    {
        struct epoll_event ev;
        ev.data.fd = sockfd;
        ev.events = events;
        int n = epoll_ctl(_epfd, EPOLL_CTL_ADD, sockfd, &ev);
        if (n < 0)
        {
            LOG(LogLevel::ERROR) << "epoll_ctl_add error";
            return;
        }
        LOG(LogLevel::INFO) << "epoll_ctl_add success" << sockfd;
    }

    // 删除event的接口
    // 删除对特定fd要关心的事件
    void DelEvent(int sockfd)
    {
        int n = epoll_ctl(_epfd, EPOLL_CTL_DEL, sockfd, nullptr);
        if (n < 0)
        {
            LOG(LogLevel::ERROR) << "epoll_ctl_del error";
            return;
        }
        LOG(LogLevel::INFO) << "epoll_ctl_del success" << sockfd;
    }

    // 修改event的接口
    // 修改对特定fd要关心的事件
    void ModEvent(int sockfd, uint32_t new_events)
    {
        struct epoll_event ev;
        ev.events = new_events;
        ev.data.fd = sockfd;
        int n = epoll_ctl(_epfd, EPOLL_CTL_MOD, sockfd, &ev);
        if (n < 0)
        {
            LOG(LogLevel::ERROR) << "epoll_ctl_mod error";
            return;
        }
        LOG(LogLevel::INFO) << "epoll_ctl_mod success" << sockfd;
    }

    // 获取就绪的fd接口
    int WaitEvents(struct epoll_event revs[], int maxnum, int timeout)
    {
        int n = epoll_wait(_epfd, revs, maxnum, timeout);
        if (n < 0)
        {
            LOG(LogLevel::WARNING) << "epoll_wait error";
        }
        else if (n == 0)
        {
            LOG(LogLevel::WARNING) << "epoll_wait timeout";
        }
        else
        {
            // 有事件就绪
        }

        return n;
    }

    ~Epoller()
    {
        if (_epfd >= 0)
        {
            close(_epfd);
        }
    }

private:
    int _epfd; // epoll模型所对应的文件描述符
};